package com.company.project.configurer;

import cn.hutool.json.JSONUtil;
import com.company.project.core.Result;
import com.company.project.dao.AdminLogMapper;
import com.company.project.model.AdminLog;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.net.openssl.ciphers.Authentication;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 使用 aop 切面记录请求日志信息
 * </p>
 *
 * @package: com.xkcoding.log.aop.aspectj
 * @description: 使用 aop 切面记录请求日志信息
 * @author: yangkai.shen
 * @date: Created in 2018/10/1 10:05 PM
 * @copyright: Copyright (c) 2018
 * @version: V1.0
 * @modified: yangkai.shen
 */
@Aspect
@Component
@Slf4j
public class AopLog {
    private static final String START_TIME = "request-start";
    @Resource
    private AdminLogMapper adminLogMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    private AdminLog log;
    /**
     * 切入点
     */
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void log1() {}
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void log2(){}
    @Pointcut("log1() || log2()")
    public void log(){}

    /**
     * 前置操作
     *
     * @param point 切入点
     */
    @Before("log()")
    public void beforeLog(JoinPoint point) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        log = new AdminLog();
        String user = (String) redisTemplate.opsForValue().get("user");
        String role = (String) redisTemplate.opsForValue().get("role");
        if(StringUtils.isNotBlank(role)) log.setRole(role);
        if(StringUtils.isNotBlank(user)) log.setUsername(user);
        log.setUrl(request.getRequestURL().toString());
        log.setIp(request.getRemoteAddr());
        log.setCreatTime(new Date());
        log.setAction(point.getSignature().getName());
        //TODO 支付成功接口log报错
        Map<String, String[]> parameterMap = request.getParameterMap();
        Long start = System.currentTimeMillis();
        request.setAttribute(START_TIME, start);
    }

    /**
     * 环绕操作
     *
     * @param point 切入点
     * @return 原方法返回值
     * @throws Throwable 异常信息
     */
    @Around("log()")
    public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
        Result result = (Result) point.proceed();
        log.setResult(JSONUtil.toJsonStr(result.getMessage()));
        return result;
    }

    /**
     * 后置操作
     */
    @AfterReturning("log()")
    public void afterReturning() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        Long start = (Long) request.getAttribute(START_TIME);
        Long end = System.currentTimeMillis();
        log.setTime(end-start + "毫秒");
        String header = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(header);
        adminLogMapper.insert(log);
    }
}
